package com.gooluke.mybatis.registar;

import com.gooluke.mybatis.handler.DefaultMethodHandler;
import com.gooluke.mybatis.handler.MethodHandler;
import com.gooluke.mybatis.handler.SqlMethodHandler;
import com.gooluke.mybatis.parser.XmlMapperParser;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class MyInterfaceFactoryBean<T> implements FactoryBean<T> {

    private final Class<T> interfaceType;
    private final Map<Method, MethodHandler> methodHandlers = new HashMap<>();
    private final Map<String, String> xmlSqlMap = new HashMap<>();
    private final DataSource dataSource;

    public MyInterfaceFactoryBean(Class<T> interfaceType) {
        this.interfaceType = interfaceType;
        // 初始化数据源（实际应该从Spring容器注入）
        this.dataSource = createDataSource();
        // 加载对应的XML文件
        loadXmlMappings();
        // 初始化方法处理器
        initMethodHandlers();
    }

    private DataSource createDataSource() {
        // 这里简单创建，实际应该从配置读取或Spring注入
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/gooluke_mybatis");
        ds.setUsername("root");
        ds.setPassword("gooluke");
        return ds;
    }

    private void loadXmlMappings() {
        try {
            String xmlPath = "classpath*:mapper/" + interfaceType.getSimpleName() + ".xml";
            Resource[] resources = new PathMatchingResourcePatternResolver().getResources(xmlPath);

            if (resources.length > 0) {
                try (InputStream inputStream = resources[0].getInputStream()) {
                    XmlMapperParser parser = new XmlMapperParser(inputStream);
                    // 将XML中的SQL语句缓存起来
                    for (Method method : interfaceType.getMethods()) {
                        String sql = parser.getSql(method.getName());
                        if (sql != null) {
                            xmlSqlMap.put(method.getName(), sql);
                        }
                    }
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("Failed to load XML mappings for " + interfaceType.getName(), e);
        }
    }

    private void initMethodHandlers() {
        for (Method method : interfaceType.getMethods()) {
            // 1. 检查是否有注解
            /*Select selectAnnotation = method.getAnnotation(Select.class);
            if (selectAnnotation != null) {
                methodHandlers.put(method, new SqlMethodHandler(selectAnnotation.value(), method, dataSource));
                continue;
            }*/

            // 2. 检查XML中是否有对应的方法
            String xmlSql = xmlSqlMap.get(method.getName());
            if (xmlSql != null) {
                methodHandlers.put(method, new SqlMethodHandler(xmlSql, method, dataSource));
                continue;
            }

            // 3. 默认处理方法
            methodHandlers.put(method, new DefaultMethodHandler(method));
        }
    }

    @Override
    public T getObject() {
        return createProxy(interfaceType, methodHandlers);
    }

    // 类型安全的代理创建方法
    @SuppressWarnings("unchecked")
    private static <T> T createProxy(Class<T> interfaceType, Map<Method, MethodHandler> methodHandlers) {
        return (T) Proxy.newProxyInstance(
                interfaceType.getClassLoader(),
                new Class[]{interfaceType},
                (proxy, method, args) -> methodHandlers.get(method).handle(args));
    }

    @Override
    public Class<?> getObjectType() {
        return interfaceType;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

}